package com.dsit.hb950;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.util.Log;

import com.dsit.hb950.file_service.FileSocketServer;
import com.google.gson.Gson;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import de.greenrobot.event.EventBus;
import protocol.ProtoMsgEncoder;
import tcp.TcpServerSocketThread;

/**
 * 通信服务类
 * Created by lxs on 2016/9/30.
 */

public class CommService extends Service {
    String TAG = "CommService";
    Timer hearbeatTimer;
    int count = 1;
    InetAddress broadcastAddr;
    TcpServerSocketThread tcpServerSocketThread;
    FileSocketServer fileSocketServer;
    PowerManager powerManager;

    HashMap<Integer, String> id_table = new HashMap<Integer, String>() {
        {
            put(0,"动力蓄电池SOC");
            put(1,"动力蓄电池电压");
            put(2,"动力蓄电池电流");
            put(3,"动力蓄电池温度MAX");
            put(4,"燃料电池功率kw");
            put(5,"燃料电池电压V");
            put(6,"燃料电池电流A");
            put(7,"氢瓶SOC% ");
            put(8,"电机功率kW");
            put(9,"PCU水温DegC");
            put(10,"动力电池入口水温DegC");
            put(11,"空调压缩机功率kW");
            put(12,"空调高压侧压力KPaG");
            put(13,"主驾空调设定温度");
            put(14,"副驾空调设定温度");
            put(15,"空调设定风速");
            put(16,"燃料电池的进口水温");
            put(17,"燃料电池的出口水温");
            put(18,"动力电池温度DegC");
            put(19,"DCF的温度：℃ ");
            put(20,"FCS基本状态");
            put(21,"FCS扩展状态");
            put(22,"FCS错误级别");
            put(23,"FCS心跳");
            put(24,"FCSHV继电器负");
            put(25,"FCSHV继电器正");
            put(26,"FCSHV继电器预充");
            put(27,"FCS非空闲允许");
            put(28,"FCS空闲启动请求");
            put(29,"PTC使能请求");
        }
    };

    class CanMessage{
        public int id;
        public String key;
        public String value;
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG,"Comm Service Started......vxxx"+ 7777);
        // getUUID();
        WifiAdapter.InitInstance(this);
        try {
            broadcastAddr = WifiAdapter.InitInstance(this).getBroadcastAddress();
            Log.e(TAG,"Broadcast addr :"+broadcastAddr.getHostAddress());
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG,"Broadcast addr error:"+e.getMessage());
        }

        startWifiAp();

        tcpServerSocketThread = new TcpServerSocketThread(30001);
        tcpServerSocketThread.setAcceptConnectionListener(new TcpServerSocketThread.AcceptConnectionListener() {
            @Override
            public void onNewClientSocketConnected(InetAddress clientAddr) {
            }
        });

        tcpServerSocketThread.setReceiveListener(new TcpServerSocketThread.ReceiveListener() {
            @Override
            public void onSocketReceived(TcpServerSocketThread server, byte[] data, int len) {
                //parse user phone cmd
            }
        });

        final CanbusDataFilter canbusDataFilter = new CanbusDataFilter();
        canbusDataFilter.setLisenter(new CanbusDataFilter.CanbusDataFilterListener() {
            @Override
            public void OnCanDataFrameReceive(ByteBuffer dataBuf) {
                parseCanMessage2(dataBuf.array(),dataBuf.array().length);
            }
        });

        final CanServerRunnable canDataReader = new CanServerRunnable();
        canDataReader.setReceiveListener(new CanServerRunnable.ReceiveListener() {
            @Override
            public void onLocalsocketReceived(byte[] data, int len) {
                Log.i(TAG,"----------> CAN reader");
                canbusDataFilter.onDataFiltering(data,len);
            }
        });

        //############# 发送心跳信息 ##########################################
        hearbeatTimer= new Timer();
        hearbeatTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                CanMessage hearbeat = new CanMessage();
                hearbeat.id = -1;
                hearbeat.key = Build.VERSION.CODENAME;//版本信息
                //Log.i(TAG,"version name:"+Build.VERSION.CODENAME);
                Gson gson = new Gson();
                String jstr = gson.toJson(hearbeat);

                ProtoMsgEncoder encoder = new ProtoMsgEncoder(0x01,"dev.heartbeat",jstr.getBytes());
                tcpServerSocketThread.equeueToSend(encoder.toBytes());// 心跳包就是发送版本信息
            }
        },1000,3*1000);

        // ##############  OTA 升级服务 #######################################
        powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
        fileSocketServer = new FileSocketServer("/cache",30005);
        fileSocketServer.setLoadingListener(new FileSocketServer.LoadingListener() {
            @Override
            public void onLoadingProgress(File file, int transferedBytes, int totalLen) {
                Log.i(TAG,"Loading files "+file.getAbsolutePath() +" done:"+100f*transferedBytes/totalLen+"%");

                UpdateEvent event = new UpdateEvent();
                event.msg = "loading";
                event.current = transferedBytes;
                event.total = totalLen;
                EventBus.getDefault().post(event);
            }

            @Override
            public void onLoadingFinish(File file) {
                UpdateEvent event = new UpdateEvent();
                event.msg = "reboot";
                EventBus.getDefault().post(event);

                if(file.getName().contains("hud")){
                    File rebootfile = new File("/cache/recovery/command");
                    if(!rebootfile.exists()){
                        try {
                            rebootfile.createNewFile();
                            FileOutputStream fileOutputStream = new FileOutputStream(rebootfile);
                            String cmd = "--update_package="+file.getAbsolutePath();
                            Log.e(TAG,"reboot command file content ="+cmd);
                            fileOutputStream.write(cmd.getBytes());
                            Log.i(TAG,"========== Reboot system...");
                            powerManager.reboot("recovery");
                        } catch (IOException e) {
                            e.printStackTrace();
                            Log.e(TAG,"error in OTA update operation:"+e.getMessage());
                        }
                    }
                }
            }

            @Override
            public void onLoadingError(Exception ex) {
                Log.e(TAG,"error in OTA file uploading:"+ex.getMessage());
                UpdateEvent event = new UpdateEvent();
                event.msg = "error";
                EventBus.getDefault().post(event);
            }
        });

        try {
            fileSocketServer.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void parseCanMessage(byte[] data,int len){
        Log.i(TAG,"----> 接收到CAN obd 数据 "+len + "字节");
        if(data!=null && data.length > 0){
            // TODO 数据加密 AES
            Log.i(TAG,"Buffer="+Utils.bytes2HexString(data,len));
            int sizeOffset = 3;
            int idSize = ((data[sizeOffset] & 0xff) << 8)|(data[sizeOffset+1] & 0xff);
            int idOffset = sizeOffset+2;
            Log.i(TAG,"ID 数量:"+idSize);
            Gson gson = new Gson();
            List<CanMessage> msgList = new ArrayList<CanMessage>();
            for(int i = 0; i < idSize; i++){

                int key =  ((data[idOffset] & 0xff) << 8) | (data[idOffset+1] & 0xff) ;
                float value = byte2floatBigEndian(data,idOffset+2);

                CanMessage canMessage = new CanMessage();
                canMessage.id = key;
                canMessage.key = id_table.get(key);
                canMessage.value = Float.toString(value);
                Log.e(TAG,"key["+i+"] int="+key+" id="+id_table.get(key) + " value="+value + " idOffset:"+idOffset);
                msgList.add(canMessage);

                // Log.e(TAG,"json string:"+jstr);
                idOffset += 6;
                if(idOffset > len - 1) {
                    break;
                }
            }
            String jstr = gson.toJson(msgList);
            // 协议消息
            ProtoMsgEncoder encoder = new ProtoMsgEncoder(0x01,"canbus.msg",jstr.getBytes());
            tcpServerSocketThread.equeueToSend(encoder.toBytes());// send by TCP
        }
    }

    void parseCanMessage2(byte[] data,int len){
        Log.i(TAG,"----> 接收到CAN obd 数据 "+len + "字节");
        if(data!=null && data.length > 0){
            // TODO 数据加密 AES
            Log.i(TAG,"Buffer="+Utils.bytes2HexString(data,len));
            int idSize = 39; // 总共有39个id
            int idOffset = 4;// id 起始 偏移量
            Log.i(TAG,"ID 数量:"+idSize);
            Gson gson = new Gson();
            List<CanMessage> msgList = new ArrayList<CanMessage>();
            for(int i = 0; i < idSize; i++){
                int key =  i;
                float value = byte2floatBigEndian(data,idOffset);

                CanMessage canMessage = new CanMessage();
                canMessage.id = key;
                canMessage.key = id_table.get(key);
                canMessage.value = Float.toString(value);
                Log.e(TAG,"key["+i+"] int="+key+" id="+id_table.get(key) + " value="+value + " idOffset:"+idOffset);
                msgList.add(canMessage);

                // Log.e(TAG,"json string:"+jstr);
                idOffset += 4;
                if(idOffset > len - 1) {
                    break;
                }
            }
            String jstr = gson.toJson(msgList);
            // 协议消息
            ProtoMsgEncoder encoder = new ProtoMsgEncoder(0x01,"canbus.msg",jstr.getBytes());
            tcpServerSocketThread.equeueToSend(encoder.toBytes());// send by TCP
        }
    }
    @Override
    public void onDestroy() {
        Log.e(TAG,"Comm Service Ended......");
        super.onDestroy();
        tcpServerSocketThread.stop();
    }


    void startWifiAp(){
        Log.i(TAG,"打开热点");
        WifiAdapter wifiAdapter = WifiAdapter.InitInstance(this);
        wifiAdapter.CloseWifiAp();
        WifiAdapter.OpenWifiThread thread = wifiAdapter.new OpenWifiThread();
        thread.start();
        Log.i(TAG,"热点 IP: "+wifiAdapter.GetWifiIP());
        Log.i(TAG,"热点广播 IP: "+wifiAdapter.GetBroadcastIP());
    }

    // 字节转浮点数，注意：这里是大端的字节序
    public static float byte2floatBigEndian(byte[] b, int index) {
        int l;
        l = b[index + 3];
        l &= 0xff;
        l |= ((long) b[index + 2] << 8);
        l &= 0xffff;
        l |= ((long) b[index + 1] << 16);
        l &= 0xffffff;
        l |= ((long) b[index + 0] << 24);
        return Float.intBitsToFloat(l);
    }

    public static float byte2floatLittleEndian(byte[] b, int index) {
        int l;
        l = b[index + 0];
        l &= 0xff;
        l |= ((long) b[index + 1] << 8);
        l &= 0xffff;
        l |= ((long) b[index + 2] << 16);
        l &= 0xffffff;
        l |= ((long) b[index + 3] << 24);
        return Float.intBitsToFloat(l);
    }
}
